/*******************************************************************************
 * Copyright (c) 2003, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM - Initial API and implementation
 *******************************************************************************/
package cn.bbstone.e4.ui.log.job;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.misc.UIStats;
import org.eclipse.ui.internal.progress.ProgressMessages;


/**
 * 
 * 
 * The UIJob is a Job that runs within the UI Thread via an asyncExec.
 *
 * @since 3.0
 * @see org.eclipse.ui.progress.UIJob
 * 
 * NOTICE: this source file is copy from {@link org.eclipse.ui.progress.UIJob}, 
 * 	and adapted to match E4 application model.
 * 
 * 
 * An Eclipse RCP application runs in one process. By default, the Eclipse framework uses a single thread to 
 * 	run all the code instructions.  This thread runs the event loop for the application. It is the only thread 
 * 	that is allowed to interact with the user interface (UI).  It is called the main thread. Sometimes it is 
 * 	also called the UI thread, but this is a misnomer as it handles all events not only the ui events.
 * 
 * @author bbstone
 *
 */
@SuppressWarnings("restriction")
public abstract class E4UIJob extends Job {

	UISynchronize sync;
	

	/**
	 * Create a new instance of the receiver with the supplied name. The display
	 * used will be the one from the workbench if this is available. UIJobs with
	 * this constructor will determine their display at runtime.
	 *
	 * @param name the job name
	 */
	public E4UIJob(UISynchronize sync, String name) {
		super(name);
		this.sync = sync;
	}

//
//	/**
//	 * Convenience method to return a status for an exception.
//	 *
//	 * @param exception the thrown exception
//	 * @return IStatus an error status built from the exception
//	 * @see Job
//	 */
//	public static IStatus errorStatus(Throwable exception) {
//		return WorkbenchPlugin.getStatus(exception);
//	}

	/**
	 * Note: this message is marked final. Implementors should use runInUIThread()
	 * instead.
	 *
	 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
	 */
	@Override
	public final IStatus run(final IProgressMonitor monitor) {
		if (monitor.isCanceled()) {
			return Status.CANCEL_STATUS;
		}
		sync.asyncExec(() -> {
			IStatus result = null;
			Throwable throwable = null;
			try {
				if (monitor.isCanceled()) {
					result = Status.CANCEL_STATUS;
				} else {
					UIStats.start(UIStats.UI_JOB, getName());
					result = runInUIThread(monitor);
				}

			} catch (Throwable t) {
				throwable = t;
			} finally {
				UIStats.end(UIStats.UI_JOB, E4UIJob.this, getName());
				if (result == null) {
					result = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
							ProgressMessages.InternalError, throwable);
				}
				done(result);
			}
		});
		return Job.ASYNC_FINISH;
	}

	/**
	 * Run the job in the UI Thread.
	 *
	 * @param monitor the monitor to be used for reporting progress and responding
	 *                to cancellation. The monitor is never <code>null</code>
	 * @return resulting status of the run. The result must not be <code>null</code>
	 */
	public abstract IStatus runInUIThread(IProgressMonitor monitor);


	
}
